<?php declare(strict_types=1);
/**
 * @author      xianganyall <xianganyall@gmail.com>
 * @copyright   2023-2025 owner
 **/

namespace Srv\Libs\Plugins\Sqls;

use Exception;
use Srv\Conf\ConfModel\AppleAuthConf;

final class SqlsSelect
{
    public const SQL_SELECT         = 'SELECT';
    public const SQL_FROM           = 'FROM';
    public const SQL_WHERE          = 'WHERE';
    public const SQL_GROUP_BY       = 'GROUP BY';
    public const SQL_HAVING         = 'HAVING';
    public const SQL_ORDER_BY       = 'ORDER BY';
    public const SQL_LIMIT          = 'LIMIT';

    public const SQL_AND            = 'AND';
    public const SQL_AS             = 'AS';
    public const SQL_OR             = 'OR';
    public const SQL_ON             = 'ON';
    public const SQL_ASC            = 'ASC';
    public const SQL_DESC           = 'DESC';
    public const SQL_DISTINCT       = 'DISTINCT';
    public const SQL_NULL           = 'NULL';

    public const SQL_WILDCARD       = '*';
    public const SQL_UNION          = 'UNION';
    public const SQL_UNION_ALL      = 'UNION ALL';
    public const INNER_JOIN         = 'INNER JOIN';
    public const LEFT_JOIN          = 'LEFT JOIN';
    public const RIGHT_JOIN         = 'RIGHT JOIN';
    public const FULL_JOIN          = 'FULL JOIN';

    private string $tableName       = '';
    private array $fieldSet         = [];
    private array $whereSet         = [];
    private array $groupBySet       = [];
    private array $havingSet        = [];
    private array $orderBySet       = [];
    private int $limitOffset        = 0;
    private int $limitRowCount      = 12;

    public function __construct(string $tableName)
    {
        $this->tableName        = $tableName;
    }

    public function setField(array $fieldSet):self
    {
        $this->fieldSet         = $fieldSet;
        return $this;
    }

    public function setWhere(array $whereSet):self
    {
        $this->whereSet         = $whereSet;
        return $this;
    }

    public function setGroupBy(array $groupBySet):self
    {
        $this->groupBySet       = $groupBySet;
        return $this;
    }

    public function setHavingSet(array $havingSet):self
    {
        $this->havingSet        = $havingSet;
        return $this;
    }

    public function setOrderBySet(array $orderBySet):self
    {
        $this->orderBySet       = $orderBySet;
        return $this;
    }

    public function setLimit(int $limitRowCount, int $limitOffset = 0):self
    {
        $this->limitRowCount    = $limitRowCount;
        $this->limitOffset      = $limitOffset;
        return $this;
    }


    private function genField():string
    {
        $fieldStr   = '';
        if(count($this->fieldSet) < 1) return $fieldStr;
        $forNum     = 0;
        foreach ($this->fieldSet as $fieldKey => $fieldVal){
            $fieldValType   = gettype($fieldVal);
            if(!in_array($fieldValType, ['string', 'integer', 'double', 'NULL'], true)) throw new Exception('Field value TypeError: '.$fieldValType);
            $fieldKeyType   = gettype($fieldKey);
            if(!in_array($fieldKeyType, ['string', 'integer'], true)) throw new Exception('Field key TypeError: '.$fieldKeyType);
            if($fieldValType === 'NULL') $fieldVal = self::SQL_NULL;
            $fieldStr       .= ($forNum < 1 ? '' : ', ').$fieldVal.($fieldKeyType !== 'string' ? '' : ' '.self::SQL_AS.' `'.$fieldKey.'`');
            ++$forNum;
        }
        return $fieldStr;
    }


    private function genWhere():string
    {
        $whereStr   = '';
        if(count($this->whereSet) < 1) return $whereStr;
        $forNum     = 0;
        foreach ($this->whereSet as $fieldKey => $fieldVal){
            $fieldValType   = gettype($fieldVal);
            if(!in_array($fieldValType, ['string', 'integer', 'double', 'NULL'], true)) throw new Exception('Field value TypeError: '.$fieldValType);
            $fieldKeyType   = gettype($fieldKey);
            if(!in_array($fieldKeyType, ['string', 'integer'], true)) throw new Exception('Field key TypeError: '.$fieldKeyType);
            if($fieldValType === 'NULL') $fieldVal = self::SQL_NULL;
            $whereStr       .= ($forNum < 1 ? '' : ', ').$fieldVal.($fieldKeyType !== 'string' ? '' : ' '.self::SQL_AS.' `'.$fieldKey.'`');
            ++$forNum;
        }
        return $whereStr;
    }

    public function toStr():string
    {
        $fieldStr   = $this->genField();
        $sql        = self::SQL_SELECT;
        if(strlen($fieldStr) > 0) $sql .= ' '.$fieldStr;
        if(strlen($this->tableName) > 0) $sql .= ' '.self::SQL_FROM.' '.$this->tableName;
//        $sql        .= ' WHERE '.$whereStr;


        return $sql;
    }


}